/*
    James McQueen, Tyson Nottingham, Michael Pogson
    TCSS 372 Winter 2012
    SC2 Simulator
    
    sc2sim.c
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "sc2sim.h"

/* Tests each of the ADTs. 
int main()
{
    srand(time(NULL));

    putchar('\n');
    testRegister();
    putchar('\n');
    testRegisterFile();
    putchar('\n');
    testMemoryModule();
    putchar('\n');
    testALU();
    putchar('\n');
    testTransfers();

    return 0;
}
*/

/******************************************************************************/
/* Register                                                                   */
/******************************************************************************/

/* Returns a RegisterPtr to a Register containing random data. */
RegisterPtr register_initialize(void)
{
    RegisterPtr r = malloc(sizeof(*r));

    *r = rand();
    /* rand() may only generate a number between 0 and 2^15 - 1, meaning the
       sign bit may not have been randomized. This fixes that. */
    *r = (rand() % 2 == 0 ? *r | SIGN_MASK : *r & ~SIGN_MASK);
    
    return r;
}

/* Returns the low order byte of the Register pointed to by r. */
uchar register_getLowByte(RegisterPtr r, int* error)
{
    if (r == NULL)
    {
        *error = NULL_POINTER_ERROR;
        return 0;
    }

    *error = NO_ERROR;
    return *r & LOB_MASK;
}

/* Returns the high order byte of the Register pointed to by r. */
uchar register_getHighByte(RegisterPtr r, int* error)
{
    if (r == NULL)
    {
        *error = NULL_POINTER_ERROR;
        return 0;
    }

    *error = NO_ERROR;
    return (*r & HOB_MASK) >> BITS_PER_BYTE;
}

/* Replaces the low order byte of the Register pointed to by r with byte.
   Returns an error code. */
int register_putLowByte(RegisterPtr r, uchar byte)
{
    if (r == NULL)
    {
        return NULL_POINTER_ERROR;
    }

    *r = (*r & ~LOB_MASK) | byte;
    return NO_ERROR;
}

/* Replaces the high order byte of the Register pointed to by r with byte.
   Returns an error code. */
int register_putHighByte(RegisterPtr r, uchar byte)
{
    if (r == NULL)
    {
        return NULL_POINTER_ERROR;
    }

    *r = (*r & ~HOB_MASK) | (byte << BITS_PER_BYTE);
    return NO_ERROR;
}

/* Returns NEGATIVE if the Register pointed to by r contains a negative number,
   NON-NEGATIVE if it is non-negative, or an error code. */
uchar register_signOf(RegisterPtr r)
{
    if (r == NULL)
    {
        return NULL_POINTER_ERROR;
    }

    return *r & SIGN_MASK ? NEGATIVE : NON_NEGATIVE;
}

/* Returns the word contained in the Register pointed to by r. */
ushort register_getValue(RegisterPtr r, int* error)
{
    if (r == NULL)
    {
        *error = NULL_POINTER_ERROR;
        return 0;
    }

    *error = NO_ERROR;
    return *r;
}

/* Replaces the contents of the Register pointed to by r with value.
   Returns an error code. */
int register_putValue(RegisterPtr r, ushort value)
{
    if (r == NULL)
    {
        return NULL_POINTER_ERROR;
    }

    *r = value;
    return NO_ERROR;
}


/******************************************************************************/
/* Register File                                                              */
/******************************************************************************/

/* Returns a RegisterFilePtr. */
RegisterFilePtr registerFile_initialize(void)
{
    RegisterFilePtr rf = malloc(sizeof(*rf) * REGISTER_COUNT);

    int i;
    for (i = 0; i < REGISTER_COUNT; ++i)
    {
        rf[i] = register_initialize();
    }

    return rf;
}
/*Returns the low Byte of the specified register. 
  Sets an out of bounds error if reg_num is greater then the register count.
  Sets a null pointer error if the pointer is null.*/
uchar registerFile_getLowByte(RegisterFilePtr rf, uchar reg_num, int* error)
{
    if (reg_num >= REGISTER_COUNT)
    {
        *error = OUT_OF_BOUNDS_ERROR;
        return(0);
    }
    else if (rf == NULL)
    {
        *error = NULL_POINTER_ERROR;
        return(0);
    }
    else
    {
        return register_getLowByte(rf[reg_num], error);
    }
}
/*Returns the high Byte of the specified register. 
  Sets an out of bounds error if reg_num is greater then the register count.
  Sets a null pointer error if the pointer is null.*/
uchar registerFile_getHighByte(RegisterFilePtr rf, uchar reg_num, int* error)
{
    if (reg_num >= REGISTER_COUNT)
    {
        *error = OUT_OF_BOUNDS_ERROR;
        return(0);
    }
    else if (rf == NULL)
    {
        *error = NULL_POINTER_ERROR;
        return(0);
    }
    else
    {
        return register_getHighByte(rf[reg_num], error);
    }
}
/*Sets the low Byte of the specified register. 
  Returns an error if reg_num is greater then the register count.
  Returns an error if the pointer is null.*/
int registerFile_putLowByte(RegisterFilePtr rf, uchar reg_num, uchar byte)
{
    if (reg_num >= REGISTER_COUNT)
    {
        return(OUT_OF_BOUNDS_ERROR);
    }
    else if (rf == NULL)
    {
        return(NULL_POINTER_ERROR);
    }
    else
    {
        return register_putLowByte(rf[reg_num], byte);
    }
}
/*Sets the High Byte of the specified register. 
  Returns an error if reg_num is greater then the register count.
  Returns an error if the pointer is null.*/
int registerFile_putHighByte(RegisterFilePtr rf, uchar reg_num, uchar byte)
{
    if (reg_num >= REGISTER_COUNT)
    {
        return(OUT_OF_BOUNDS_ERROR);
    }
    else if (rf == NULL)
    {
        return(NULL_POINTER_ERROR);
    }
    else
    {
        return register_putHighByte(rf[reg_num], byte);
    }
}
/*Returns the word contained in the specified register. 
  Sets an out of bounds error if reg_num is greater then the register count.
  Sets a null pointer error if the pointer is null.*/
ushort registerFile_getWord(RegisterFilePtr rf, uchar reg_num, int* error)
{
    if (reg_num >= REGISTER_COUNT)
    {
        *error = OUT_OF_BOUNDS_ERROR;
        return(0);
    }
    else if (rf == NULL)
    {
        *error = NULL_POINTER_ERROR;
        return(0);
    }
    else
    {
        return register_getValue(rf[reg_num], error);
    }
}
/*Sets a given value of the specified register. 
  Sets an out of bounds error if reg_num is greater then the register count.
  Sets a null pointer error if the pointer is null.*/
int registerFile_putWord(RegisterFilePtr rf, uchar reg_num, ushort word)
{
    if (reg_num >= REGISTER_COUNT)
    {
        return OUT_OF_BOUNDS_ERROR;
    }
    else if (rf == NULL)
    {
        return NULL_POINTER_ERROR;
    }
    else
    {
        return register_putValue(rf[reg_num], word);
    }
}


/******************************************************************************/
/* Memory Module                                                              */
/******************************************************************************/
MemoryModulePtr memory_initialize(void)
{
    /* Initialize the MemoryModule by allocating enough memory for all possible storage
     scenarios */
    MemoryModulePtr mm = malloc(MEMORY_SPACE - MEMORY_START_ADDRESS);
    return mm;
}
/* Retrieve a byte from memory at the specified address. */
uchar memory_getByte(MemoryModulePtr mm, ushort address, int* error)
{
    /*  Check the boundary of the address specified to ensure valid address parameter. */
    if (address < MEMORY_START_ADDRESS)
    {
        *error = OUT_OF_BOUNDS_ERROR;
        return 0;
    }
    /* If (mm != NULL): It is possible to retrieve the byte located at the address specified, 
     since the address is asserted to be valid at this point. */
    else if (mm)
    {
        *error = NO_ERROR;
        return mm[address - MEMORY_START_ADDRESS];
    }
    /* The memory module was null so we set the error code to indicate null pointer */
    else
    {
        *error = NULL_POINTER_ERROR;
        return 0;
    }
}
/* Place a byte into memory at a specified address. */
int memory_putByte(MemoryModulePtr mm, ushort address, uchar byte)
{
    /* Check the boundary of the address specified to ensure valid address parameter. */
    if (address < MEMORY_START_ADDRESS)
    {
        return OUT_OF_BOUNDS_ERROR;
    }
    /* If (mm != NULL): It is possible to place the byte located at the address specifed, 
     since the address is asserted to be valid at this point. */
    else if (mm)
    {
        mm[address - MEMORY_START_ADDRESS] = byte;
        return NO_ERROR;
    }
    /* The memory module was null so we return the error code */
    else
    {
        return NULL_POINTER_ERROR;
    }
}
/* Retrieve a word from memory at the specified address. */
ushort memory_getWord(MemoryModulePtr mm, ushort address, int* error)
{
    /*  Check the boundary of the address specified to ensure valid address parameter. */
    if (address < MEMORY_START_ADDRESS || address >= MEMORY_SPACE - 1) 
    {
        *error = OUT_OF_BOUNDS_ERROR;
        return 0;
    }
    /* If (mm != NULL): It is possible to retrieve the word located at the address specified, 
     since the address is asserted to be valid at this point. */
    else if (mm)  
    {
        ushort word;
        word = memory_getByte(mm, address, error);
        word = word << BITS_PER_BYTE;
        word |= memory_getByte(mm, address + 1, error);
        *error = NO_ERROR;
        return word;
    }
    /* The memory module was null so we set the error code to indicate null pointer */
    else
    {
        *error = NULL_POINTER_ERROR;
        return 0;
    }
}
/* Place a word into memory at a specified address. */
int memory_putWord(MemoryModulePtr mm, ushort address, ushort word)
{
    /* Check the boundary of the address specified to ensure valid address parameter. */
    if (address < MEMORY_START_ADDRESS || address >= MEMORY_SPACE - 1)
    {
        return OUT_OF_BOUNDS_ERROR;
    }
    /* If (mm != NULL): It is possible to place the word located at the address specifed, 
     since the address is asserted to be valid at this point. */
    else if (mm)
    {
        uchar hob = (word & HOB_MASK) >> BITS_PER_BYTE;
        memory_putByte(mm, address, hob);
        uchar lob = word;
        memory_putByte(mm, address + 1, lob);
        return NO_ERROR;
    }
    /* The memory module was null so we return the error code */
    else
    {
        return NULL_POINTER_ERROR;
    }
}


/******************************************************************************/
/* ALU                                                                        */
/******************************************************************************/

/* Returns an ALUPtr to an ALU, or NULL if sw or rf are NULL. */
ALUPtr alu_initialize(RegisterPtr sw, RegisterFilePtr rf)
{
    if (sw == NULL || rf == NULL)
    {
        return NULL;
    }

    ALUPtr alu = malloc(sizeof(*alu));
    alu->SW = sw;
    alu->rf = rf;

    return alu;
}

/* Puts word into operand A of the ALU pointed to by alu.
   Returns an error code. */
int alu_putOperandA(ALUPtr alu, ushort word)
{
    if (alu)
    {
        return register_putValue(&alu->A, word);
    }
    else
    {
        return NULL_POINTER_ERROR;
    }
}

/* Puts word into operand B of the ALU pointed to by alu.
   Returns an error code. */
int alu_putOperandB(ALUPtr alu, ushort word)
{
    if (alu)
    {
        return register_putValue(&alu->B, word);
    }
    else
    {
        return NULL_POINTER_ERROR;
    }
}

/* Returns the result of most recent operation of the ALU pointed to by alu. */
ushort alu_getResult(ALUPtr alu, int* error)
{
    if (alu)
    {
        return register_getValue(&alu->R, error);
    }
    else
    {
        *error = NULL_POINTER_ERROR;
        return 0;
    }
}

/* Clears the flags of the status word.
   Returns an error code. */
int alu_clearFlags(ALUPtr alu)
{
    if (alu == NULL)
    {
        return NULL_POINTER_ERROR;
    }

    *(alu->SW) &= ~FLAGS_MASK;

    return NO_ERROR;
}

/* Sets the flags of the status word relevant to all types of ALU operations.
   Returns an error code. */
int alu_setFlags(ALUPtr alu)
{
    if (alu == NULL)
    {
        return NULL_POINTER_ERROR;
    }

    int error;
    ushort result = register_getValue(&alu->R, &error);

    if (result & SIGN_MASK)
    {
        *(alu->SW) |= N_MASK;
    }
    else if (result == 0)
    {
        *(alu->SW) |= Z_MASK;
    }

    return NO_ERROR;
}

/* Sets the flags the status word relevant to the addition operation.
   Returns an error code. */
int alu_setFlagsAdd(ALUPtr alu)
{
    if (alu == NULL)
    {
        return NULL_POINTER_ERROR;
    }

    uchar aSign = register_signOf(&alu->A);
    uchar bSign = register_signOf(&alu->B);
    uchar rSign = register_signOf(&alu->R);

    /* There must be a carry if the leftmost bits of A and B are both 1,
       or if either of the bits is 1 and the result's leftmost bit is 0. */
    if ((aSign && bSign) || ((aSign != bSign) && !rSign))
    {
        *(alu->SW) |= C_MASK;
    }

    /* There must be an overflow if A and B both have the same sign,
       but the result's sign is different. */
    if ((aSign == bSign) && (rSign != aSign))
    {
        *(alu->SW) |= O_MASK;
    }

    return NO_ERROR;
}

/* Sets the flags the status word relevant to the subtraction operation.
   Returns an error code. */
int alu_setFlagsSub(ALUPtr alu)
{
    if (alu == NULL)
    {
        return NULL_POINTER_ERROR;
    }

    /* This uses the identity A - B = A + (-B) to allow alu_setFlagsAdd()
       to handle flag generation. This assumes that this is how the SC-2
       handles the carry flag with subtraction. */
    register_putValue(&alu->B, -(alu->B));
    alu_setFlagsAdd(alu);
    register_putValue(&alu->B, -(alu->B));

    return NO_ERROR;
}

/* Sets the flags the status word relevant to the multiplication operation.
   Returns an error code. */
int alu_setFlagsMul(ALUPtr alu)
{
    if (alu == NULL)
    {
        return NULL_POINTER_ERROR;
    }

    /* Test the full result of the multiplication rather than just the contents
       of the result Register, which is only one word of a two word result. */
    if (alu->A * alu->B == 0)
    {
        *(alu->SW) |= Z_MASK;
    }

    return NO_ERROR;
}

/* Sets the flags the status word relevant to the shift left operation.
   Returns an error code. */
int alu_setFlagsShl(ALUPtr alu)
{
    if (alu == NULL)
    {
        return NULL_POINTER_ERROR;
    }

    /* If operand A had a sign bit, it would be shifted left, and would generate
       a carry bit. */
    if (register_signOf(&alu->A) == NEGATIVE)
    {
        *(alu->SW) |= C_MASK;
    }

    return NO_ERROR;
}

int alu_execute(ALUPtr alu, ushort operation, ushort op1, ushort op2)
{
    if (alu == NULL)
    {
        return NULL_POINTER_ERROR;
    }
    
    alu_putOperandA(alu, op1);
    alu_putOperandB(alu, op2);

    switch (operation)
    {
    case ADD: alu_add(alu); break;
    case SUB: alu_sub(alu); break;
    case MUL: alu_mul(alu); break;
    case DIV: alu_div(alu); break;
    case AND: alu_and(alu); break;
    case OR: alu_or(alu); break;
    case XOR: alu_xor(alu); break;
    case NOT: alu_not(alu); break;
    case SHL: alu_shl(alu); break;
    case SHR: alu_shr(alu); break;
    default: return INVALID_INSTRUCTION_ERROR;
    }

    return NO_ERROR;
}

/* Adds operand A and operand B, stores the result, and sets condition codes.
   Returns an error code. */
int alu_add(ALUPtr alu)
{

    if (alu)
    {
        alu_clearFlags(alu);
        register_putValue(&alu->R, register_getValue(&alu->A, &error) + register_getValue(&alu->B, &error));
        alu_setFlags(alu);
        alu_setFlagsAdd(alu);
        return NO_ERROR;
    }
    else
    {
        return NULL_POINTER_ERROR;
    }
}

/* Subtracts operand B from operand A, stores the result, and sets condition codes.
   Returns an error code. */
int alu_sub(ALUPtr alu)
{
    if (alu)
    {
        alu_clearFlags(alu);
        register_putValue(&alu->R, register_getValue(&alu->A, &error) - register_getValue(&alu->B, &error));
        alu_setFlags(alu);
        alu_setFlagsSub(alu);
        return NO_ERROR;
    }
    else
    {
        return NULL_POINTER_ERROR;
    }
}

/* Multiplies operand A and operand B, stores the high order word of the result
   to R8, the low order word of the result to R9, and sets condition codes.
   Returns an error code. */
int alu_mul(ALUPtr alu)
{
    if (alu)
    {
        alu_clearFlags(alu);

        /* These casts preserve the bit pattern of the unsigned short, and allow
           the C multiplication operator to generate the correct result. */
        short a = (short) register_getValue(&alu->A, &error);
        short b = (short) register_getValue(&alu->B, &error);
		
        register_putValue(&alu->R, a * b & LOW_MASK);                          /* LOW */
        registerFile_putWord(alu->rf, R9, alu->R);
        register_putValue(&alu->R,((a * b) & HOW_MASK) >> BITS_PER_WORD);     /* HOW */
        registerFile_putWord(alu->rf, R8, alu->R);
        /* Must do HOW second so alu_setFlags() can detect the sign bit. */
        alu_setFlags(alu);
        alu_setFlagsMul(alu);
        return NO_ERROR;
    }
    else
    {
        return NULL_POINTER_ERROR;
    }
}

/* Divides operand B from operand A, stores the integer quotient to R8, the
   remainder to R9, and sets condition codes. If operand B is zero, the
   operation is not performed and no results are stored.
   Returns an error code. */
int alu_div(ALUPtr alu)
{
    if (alu)
    {
        alu_clearFlags(alu);
        if (alu->B != 0)
        {
            /* These casts preserve the bit pattern of the unsigned short, and allow
               the C division/mod operator to generate the correct result. */
            short a = (short) register_getValue(&alu->A, &error);
			short b = (short) register_getValue(&alu->B, &error);

            register_putValue(&alu->R, a % b);
            registerFile_putWord(alu->rf, R9, alu->R);
            register_putValue(&alu->R, a / b);
            registerFile_putWord(alu->rf, R8, alu->R);
            /* Set flags based on the result of division rather than mod. */
            alu_setFlags(alu);
        }
        return NO_ERROR;
    }
    else
    {
        return NULL_POINTER_ERROR;
    }
}

/* ANDs operand A and operand B, stores the result, and sets condition codes.
   Returns an error code. */
int alu_and(ALUPtr alu)
{
    if (alu)
    {
        alu_clearFlags(alu);
         register_putValue(&alu->R, register_getValue(&alu->A, &error) & register_getValue(&alu->B, &error));
        alu_setFlags(alu);
        return NO_ERROR;
    }
    else
    {
        return NULL_POINTER_ERROR;
    }
}

/* ORs operand A and operand B, stores the result, and sets condition codes.
   Returns an error code. */
int alu_or(ALUPtr alu)
{
    if (alu)
    {
        alu_clearFlags(alu);
         register_putValue(&alu->R, register_getValue(&alu->A, &error) | register_getValue(&alu->B, &error));
        alu_setFlags(alu);
        return NO_ERROR;
    }
    else
    {
        return NULL_POINTER_ERROR;
    }
}

/* XORs operand A and operand B, stores the result, and sets condition codes.
   Returns an error code. */
int alu_xor(ALUPtr alu)
{
    if (alu)
    {
        alu_clearFlags(alu);
         register_putValue(&alu->R, register_getValue(&alu->A, &error) ^ register_getValue(&alu->B, &error));
        alu_setFlags(alu);
        return NO_ERROR;
    }
    else
    {
        return NULL_POINTER_ERROR;
    }
}

/* NOTs operand A, stores the result, and sets condition codes.
   Returns an error code. */
int alu_not(ALUPtr alu)
{
    if (alu)
    {
        alu_clearFlags(alu);
        int temp = register_getValue(&alu->A, &error);
        register_putValue(&alu->R, ~temp);
        alu_setFlags(alu);
        return NO_ERROR;
    }
    else
    {
        return NULL_POINTER_ERROR;
    }
}

/* Left shifts operand A by one bit, stores the result, and sets condition codes.
   Returns an error code. */
int alu_shl(ALUPtr alu)
{
    if (alu)
    {
        alu_clearFlags(alu);
        int temp = register_getValue(&alu->A, &error);
        register_putValue(&alu->R, temp << 1);
        alu_setFlags(alu);
        alu_setFlagsShl(alu);
        return NO_ERROR;
    }
    else
    {
        return NULL_POINTER_ERROR;
    }
}

/* Right shifts operand A by one bit, stores the result, and sets condition codes.
   Returns an error code. */
int alu_shr(ALUPtr alu)
{
    if (alu)
    {
        alu_clearFlags(alu);
        int temp = register_getValue(&alu->A, &error);
        register_putValue(&alu->R,temp >> 1);
        alu_setFlags(alu);
        return NO_ERROR;
    }
    else
    {
        return NULL_POINTER_ERROR;
    }
}

/* Tests the Register ADT. */
void testRegister(void)
{
    printBanner("REGISTER TESTS");

    /* Null pointer error tests. */
    RegisterPtr r = NULL;
    printf("\nTesting Register error codes with null pointer...\n");

    int error = NO_ERROR;
    register_getLowByte(r, &error);
    printf("Testing register_getLowByte:\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    register_getHighByte(r, &error);
    printf("Testing register_getHighByte:\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = register_putLowByte(r, 0);
    printf("Testing register_putLowByte:\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = register_putHighByte(r, 0);
    printf("Testing register_putHighByte:\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = register_signOf(r);
    printf("Testing register_signOf:\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    register_getValue(r, &error);
    printf("Testing register_getValue:\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = register_putValue(r, 0);
    printf("Testing register_putValue:\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);


    /* No error tests. */
    r = register_initialize();
    printf("\nTesting Register error codes with normal input...\n");

    error = NO_ERROR;
    register_getLowByte(r, &error);
    printf("Testing register_getLowByte:\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    register_getHighByte(r, &error);
    printf("Testing register_getHighByte:\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = register_putLowByte(r, 0);
    printf("Testing register_putLowByte:\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = register_putHighByte(r, 0);
    printf("Testing register_putHighByte:\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = register_signOf(r);
    printf("Testing register_signOf:\tExpected value #: 0. Actual value #: %i.\n", error);

    error = NO_ERROR;
    register_getValue(r, &error);
    printf("Testing register_getValue:\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = register_putValue(r, 0);
    printf("Testing register_putValue:\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);


    /* Get/set tests. */
    uchar low  = 0x42;
    uchar high = 0xf0;
    ushort word = 0x1234;

    printf("\nTesting Register get/set functions...\n");
    register_putLowByte(r, low);
    printf("Testing put/getLowByte:\t\tPut %u, got %u from low byte.\n", low, register_getLowByte(r, &error));

    register_putHighByte(r, high);
    printf("Testing put/getHighByte:\tPut %u, got %u from high byte.\n", high, register_getHighByte(r, &error));

    printf("Expected register value: %hu. Actual register value: %hu.\n", (high << BITS_PER_BYTE) | low, register_getValue(r, &error));

    printf("Testing register_signOf:\tExpected output: 1. Actual output: %u.\n", register_signOf(r));

    register_putValue(r, word);
    printf("Testing put/getValue:\t\tPut %hu, got %hu from register.\n", word, register_getValue(r, &error));

    printf("Testing register_signOf:\tExpected output: 0. Actual output: %u.\n", register_signOf(r));
}

/* Tests the RegisterFile ADT. */
void testRegisterFile(void)
{
    printBanner("REGISTER FILE TESTS");

    /* Null pointer error tests. */
    RegisterFilePtr rf = NULL;
    printf("\nTesting RegisterFile error codes with null pointer...\n");

    int error = NO_ERROR;
    registerFile_getLowByte(rf, 0, &error);
    printf("Testing registerFile_getLowByte:\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    registerFile_getHighByte(rf, 0, &error);
    printf("Testing registerFile_getHighByte:\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = registerFile_putLowByte(rf, 0, 0);
    printf("Testing registerFile_putLowByte:\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = registerFile_putHighByte(rf, 0, 0);
    printf("Testing registerFile_putHighByte:\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    registerFile_getWord(rf, 0, &error);
    printf("Testing registerFile_getWord:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = registerFile_putWord(rf, 0, 0);
    printf("Testing registerFile_putWord:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);


    /* Out of bounds tests. */
    rf = registerFile_initialize();
    printf("\nTesting RegisterFile error codes with invalid register number...\n");

    error = NO_ERROR;
    registerFile_getLowByte(rf, REGISTER_COUNT, &error);
    printf("Testing registerFile_getLowByte:\tExpected error #: %i. Actual error #: %i.\n", OUT_OF_BOUNDS_ERROR, error);

    error = NO_ERROR;
    registerFile_getHighByte(rf, 17, &error);
    printf("Testing registerFile_getHighByte:\tExpected error #: %i. Actual error #: %i.\n", OUT_OF_BOUNDS_ERROR, error);

    error = NO_ERROR;
    error = registerFile_putLowByte(rf, 18, 0);
    printf("Testing registerFile_putLowByte:\tExpected error #: %i. Actual error #: %i.\n", OUT_OF_BOUNDS_ERROR, error);

    error = NO_ERROR;
    error = registerFile_putHighByte(rf, -100, 0);
    printf("Testing registerFile_putHighByte:\tExpected error #: %i. Actual error #: %i.\n", OUT_OF_BOUNDS_ERROR, error);

    error = NO_ERROR;
    registerFile_getWord(rf, 255, &error);
    printf("Testing registerFile_getWord:\t\tExpected error #: %i. Actual error #: %i.\n", OUT_OF_BOUNDS_ERROR, error);

    error = NO_ERROR;
    error = registerFile_putWord(rf, -1, 0);
    printf("Testing registerFile_putWord:\t\tExpected error #: %i. Actual error #: %i.\n", OUT_OF_BOUNDS_ERROR, error);


    /* No error tests. */
    printf("\nTesting RegisterFile error codes with normal input...\n");

    error = NO_ERROR;
    registerFile_getLowByte(rf, 0, &error);
    printf("Testing registerFile_getLowByte:\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    registerFile_getHighByte(rf, 0, &error);
    printf("Testing registerFile_getHighByte:\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = registerFile_putLowByte(rf, 0, 0);
    printf("Testing registerFile_putLowByte:\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = registerFile_putHighByte(rf, 0, 0);
    printf("Testing registerFile_putHighByte:\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    registerFile_getWord(rf, 0, &error);
    printf("Testing registerFile_getWord:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = registerFile_putWord(rf, 0, 0);
    printf("Testing registerFile_putWord:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);


    /* Get/set tests. */
    uchar  low  = 0x42;
    uchar  high = 0xf0;
    ushort word = 0x1234;

    printf("\nTesting RegisterFile get/set functions...\n");
    registerFile_putLowByte(rf, 0, low);
    printf("Testing put/getLowByte:\t\tPut %u, got %u from low byte.\n", low, registerFile_getLowByte(rf, 0, &error));

    registerFile_putHighByte(rf, 0, high);
    printf("Testing put/getHighByte:\tPut %u, got %u from high byte.\n", high, registerFile_getHighByte(rf, 0, &error));

    printf("Expected register value: %hu. Actual register value: %hu.\n", (high << BITS_PER_BYTE) | low, registerFile_getWord(rf, 0, &error));

    registerFile_putWord(rf, REGISTER_COUNT - 1, word);
    printf("Testing put/getValue:\t\tPut %hu, got %hu from register.\n", word, registerFile_getWord(rf, REGISTER_COUNT - 1, &error));
}

/* Tests the MemoryModule ADT. */
void testMemoryModule(void)
{
    printBanner("MEMORY MODULE TESTS");

    /* Null pointer error tests. */
    MemoryModulePtr mm = NULL;
    printf("\nTesting MemoryModule error codes with null pointer...\n");

    int error = NO_ERROR;
    memory_getByte(mm, MEMORY_START_ADDRESS, &error);
    printf("Testing memory_getByte:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = memory_putByte(mm, MEMORY_START_ADDRESS, 0);
    printf("Testing memory_putByte:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    memory_getWord(mm, MEMORY_START_ADDRESS, &error);
    printf("Testing memory_getWord:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = memory_putWord(mm, MEMORY_START_ADDRESS, 0);
    printf("Testing memory_putWord:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);


    /* Out of bounds tests. */
    mm = memory_initialize();
    printf("\nTesting MemoryModule error codes with invalid address...\n");

    error = NO_ERROR;
    memory_getByte(mm, MEMORY_START_ADDRESS - 1, &error);
    printf("Testing memory_getByte:\t\tExpected error #: %i. Actual error #: %i.\n", OUT_OF_BOUNDS_ERROR, error);

    error = NO_ERROR;
    error = memory_putByte(mm, 0x100, 0);
    printf("Testing memory_putByte:\t\tExpected error #: %i. Actual error #: %i.\n", OUT_OF_BOUNDS_ERROR, error);

    error = NO_ERROR;
    memory_getWord(mm, MEMORY_SPACE - 1, &error);
    printf("Testing memory_getWord:\t\tExpected error #: %i. Actual error #: %i.\n", OUT_OF_BOUNDS_ERROR, error);

    error = NO_ERROR;
    error = memory_putWord(mm, 0, 0);
    printf("Testing memory_putWord:\t\tExpected error #: %i. Actual error #: %i.\n", OUT_OF_BOUNDS_ERROR, error);


    /* No error tests. */
    printf("\nTesting MemoryModule error codes with normal input...\n");

    error = NO_ERROR;
    memory_getByte(mm, MEMORY_START_ADDRESS, &error);
    printf("Testing memory_getByte:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = memory_putByte(mm, MEMORY_START_ADDRESS + 1, 0);
    printf("Testing memory_putByte:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    memory_getWord(mm, MEMORY_SPACE - 2, &error);
    printf("Testing memory_getWord:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = memory_putWord(mm, 0x7777, 0);
    printf("Testing memory_putWord:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);


    /* Get/set tests. */
    uchar low = 0x42;
    uchar high = 0xf0;
    ushort word = 0x1234;

    printf("\nTesting MemoryModule get/set functions...\n");
    memory_putByte(mm, MEMORY_START_ADDRESS, high);
    printf("Testing memory_putByte:\t\tPut %u, got %u.\n", high, memory_getByte(mm, MEMORY_START_ADDRESS, &error));

    memory_putByte(mm, MEMORY_START_ADDRESS + 1, low);
    printf("Testing memory_putByte:\t\tPut %u, got %u.\n", low, memory_getByte(mm, MEMORY_START_ADDRESS + 1, &error));

    printf("Expected word value at 0x%x: %hu. Actual value: %hu.\n", MEMORY_START_ADDRESS, (high << BITS_PER_BYTE) | low, memory_getWord(mm, MEMORY_START_ADDRESS, &error));

    memory_putWord(mm, MEMORY_SPACE - 2, word);
    printf("Testing memory_putWord:\t\tPut %hu, got %hu.\n", word, memory_getWord(mm, MEMORY_SPACE - 2, &error));
}

/* Tests the ALU ADT. */
void testALU(void)
{
    printBanner("ALU TESTS");

    /* Null pointer error tests. */
    ALUPtr alu = NULL;

    printf("\nTesting ALU error codes with null pointer...\n");

    int error = NO_ERROR;
    error = alu_putOperandA(alu, 0);
    printf("Testing alu_putOperandA:\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = alu_putOperandB(alu, 0);
    printf("Testing alu_putOperandB:\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    alu_getResult(alu, &error);
    printf("Testing alu_getResult:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = alu_clearFlags(alu);
    printf("Testing alu_clearFlags:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = alu_setFlags(alu);
    printf("Testing alu_setFlags:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);
    
    /*
    error = NO_ERROR;
    error = alu_getOperation(alu, ADD);
    printf("Testing alu_getOperation:\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);
    */
    
    error = NO_ERROR;
    error = alu_add(alu);
    printf("Testing alu_add:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = alu_sub(alu);
    printf("Testing alu_sub:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = alu_mul(alu);
    printf("Testing alu_mul:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = alu_div(alu);
    printf("Testing alu_div:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = alu_and(alu);
    printf("Testing alu_and:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = alu_or(alu);
    printf("Testing alu_or:\t\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = alu_xor(alu);
    printf("Testing alu_xor:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = alu_not(alu);
    printf("Testing alu_not:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = alu_shl(alu);
    printf("Testing alu_shl:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);

    error = NO_ERROR;
    error = alu_shr(alu);
    printf("Testing alu_shr:\t\tExpected error #: %i. Actual error #: %i.\n", NULL_POINTER_ERROR, error);


    /* Invalid opcode error test */
    RegisterPtr     sw = register_initialize();
    RegisterFilePtr rf = registerFile_initialize();
    alu = alu_initialize(sw, rf);
    printf("\nTesting ALU error codes with invalid opcode...\n");

    /*
    error = NO_ERROR;
    error = alu_getOperation(alu, 999);
    printf("Testing alu_getOperation:\tExpected error #: %i. Actual error #: %i.\n", INVALID_INSTRUCTION_ERROR, error);
    */

    /* No error tests. */
    printf("\nTesting ALU error codes with normal input...\n");

    error = NO_ERROR;
    error = alu_putOperandA(alu, 0);
    printf("Testing alu_putOperandA:\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = alu_putOperandB(alu, 0);
    printf("Testing alu_putOperandB:\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    alu_getResult(alu, &error);
    printf("Testing alu_getResult:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = alu_clearFlags(alu);
    printf("Testing alu_clearFlags:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = alu_setFlags(alu);
    printf("Testing alu_setFlags:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    /*
    error = NO_ERROR;
    error = alu_getOperation(alu, ADD);
    printf("Testing alu_getOperation:\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);
    */
    
    error = NO_ERROR;
    error = alu_add(alu);
    printf("Testing alu_add:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = alu_sub(alu);
    printf("Testing alu_sub:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = alu_mul(alu);
    printf("Testing alu_mul:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = alu_div(alu);
    printf("Testing alu_div:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = alu_and(alu);
    printf("Testing alu_and:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = alu_or(alu);
    printf("Testing alu_or:\t\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = alu_xor(alu);
    printf("Testing alu_xor:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = alu_not(alu);
    printf("Testing alu_not:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = alu_shl(alu);
    printf("Testing alu_shl:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);

    error = NO_ERROR;
    error = alu_shr(alu);
    printf("Testing alu_shr:\t\tExpected error #: %i. Actual error #: %i.\n", NO_ERROR, error);


    /* ALU function tests. */
    short a = -1234;
    short b = 12345;

    printf("\nTesting ALU functions with A = %#.4hx, B = %#.4hx...\n", a, b);

    alu_putOperandA(alu, a);
    alu_putOperandB(alu, b);

    alu_add(alu);
    printf("Testing alu_add:\t\tExpected result: %#.4hx. Actual result: %#.4hx.\n", a + b, alu_getResult(alu, &error));
    printf("NZCO: %i%i%i%i\n", (*(alu->SW) & N_MASK) >> 15, (*(alu->SW) & Z_MASK) >> 14, (*(alu->SW) & C_MASK) >> 13, (*(alu->SW) & O_MASK) >> 13);

    alu_sub(alu);
    printf("Testing alu_sub:\t\tExpected result: %#.4hx. Actual result: %#.4hx.\n", a - b, alu_getResult(alu, &error));
    printf("NZCO: %i%i%i%i\n", (*(alu->SW) & N_MASK) >> 15, (*(alu->SW) & Z_MASK) >> 14, (*(alu->SW) & C_MASK) >> 13, (*(alu->SW) & O_MASK) >> 13);

    alu_mul(alu);
    unsigned int how = registerFile_getWord(rf, R8, &error) << BITS_PER_WORD;
    unsigned int low = registerFile_getWord(rf, R9, &error);
    printf("Testing alu_mul:\t\tExpected result: %#.8x. Actual result: %#.8x.\n", a * b, how + low);
    printf("NZCO: %i%i%i%i\n", (*(alu->SW) & N_MASK) >> 15, (*(alu->SW) & Z_MASK) >> 14, (*(alu->SW) & C_MASK) >> 13, (*(alu->SW) & O_MASK) >> 13);

    alu_div(alu);
    printf("Testing alu_div (div):\t\tExpected result: %#.4hx. Actual result: %#.4hx.\n", a / b, registerFile_getWord(rf, R8, &error));
    printf("Testing alu_div (mod):\t\tExpected result: %#.4hx. Actual result: %#.4hx.\n", a % b, registerFile_getWord(rf, R9, &error));
    printf("NZCO: %i%i%i%i\n", (*(alu->SW) & N_MASK) >> 15, (*(alu->SW) & Z_MASK) >> 14, (*(alu->SW) & C_MASK) >> 13, (*(alu->SW) & O_MASK) >> 13);

    alu_and(alu);
    printf("Testing alu_and:\t\tExpected result: %#.4hx. Actual result: %#.4hx.\n", a & b, alu_getResult(alu, &error));
    printf("NZCO: %i%i%i%i\n", (*(alu->SW) & N_MASK) >> 15, (*(alu->SW) & Z_MASK) >> 14, (*(alu->SW) & C_MASK) >> 13, (*(alu->SW) & O_MASK) >> 13);

    alu_or(alu);
    printf("Testing alu_or:\t\t\tExpected result: %#.4hx. Actual result: %#.4hx.\n", a | b, alu_getResult(alu, &error));
    printf("NZCO: %i%i%i%i\n", (*(alu->SW) & N_MASK) >> 15, (*(alu->SW) & Z_MASK) >> 14, (*(alu->SW) & C_MASK) >> 13, (*(alu->SW) & O_MASK) >> 13);

    alu_xor(alu);
    printf("Testing alu_xor:\t\tExpected result: %#.4hx. Actual result: %#.4hx.\n", a ^ b, alu_getResult(alu, &error));
    printf("NZCO: %i%i%i%i\n", (*(alu->SW) & N_MASK) >> 15, (*(alu->SW) & Z_MASK) >> 14, (*(alu->SW) & C_MASK) >> 13, (*(alu->SW) & O_MASK) >> 13);

    alu_not(alu);
    printf("Testing alu_not:\t\tExpected result: %#.4hx. Actual result: %#.4hx.\n", ~a, alu_getResult(alu, &error));
    printf("NZCO: %i%i%i%i\n", (*(alu->SW) & N_MASK) >> 15, (*(alu->SW) & Z_MASK) >> 14, (*(alu->SW) & C_MASK) >> 13, (*(alu->SW) & O_MASK) >> 13);

    alu_shl(alu);
    printf("Testing alu_shl:\t\tExpected result: %#.4hx. Actual result: %#.4hx.\n", a << 1, alu_getResult(alu, &error));
    printf("NZCO: %i%i%i%i\n", (*(alu->SW) & N_MASK) >> 15, (*(alu->SW) & Z_MASK) >> 14, (*(alu->SW) & C_MASK) >> 13, (*(alu->SW) & O_MASK) >> 13);

    alu_shr(alu);
    /* Have to cast a to unsigned because my system uses right arithmetic shift on signed operands, but SC-2 does logical right shift. */
    printf("Testing alu_shr:\t\tExpected result: %#.4hx. Actual result: %#.4hx.\n", (ushort) a >> 1, alu_getResult(alu, &error));
    printf("NZCO: %i%i%i%i\n", (*(alu->SW) & N_MASK) >> 15, (*(alu->SW) & Z_MASK) >> 14, (*(alu->SW) & C_MASK) >> 13, (*(alu->SW) & O_MASK) >> 13);
}

/* Tests data transfers between the ADTs. */
void testTransfers(void)
{
    printBanner("DATA TRANSFER TESTS");
    /* tests from register to memory*/
    int error = NO_ERROR;
    RegisterFilePtr rf;
    rf = registerFile_initialize();
    MemoryModulePtr mm;
    mm = memory_initialize();

    uchar regnum  = 0xA;
    ushort word = 0x1234;
    ushort address = 0x8100;

    printf("\n Testing from registerFile to memory!(word)");
    registerFile_putWord(rf, regnum, word);
    memory_putWord(mm, address, registerFile_getWord(rf, regnum, &error));
    printf("\n testing to see if %hu got put into memory %hu from register, memory was: %hu.", word, address, memory_getWord(mm, address, &error));

    printf("\n\n Testing from memory to register file (word)");

    address = 0x8150;
    word = 0x2314;
    regnum  = 0xF;
    memory_putWord(mm, address, word);
    registerFile_putWord(rf, regnum, memory_getWord(mm, address, &error));
    printf("\n testing to see if %hu got put into registerFile %u from memory, registerFile was: %hu.", word, regnum, registerFile_getWord(rf, regnum, &error));

    printf("\n\n testing from registerFile to memory (byte)");

    memory_putByte(mm, address, registerFile_getLowByte(rf, regnum, &error));
    printf("\n testing to see if %hu got put into memory %hu from register, memory was: %hu.", registerFile_getLowByte(rf, regnum, &error), address, memory_getByte(mm, address, &error));

    printf("\n\n testing from memory to registerFile (byte)");

    address = 0x8100;
    regnum  = 0xA;
    registerFile_putLowByte(rf, regnum, memory_getByte(mm, address, &error));
    printf("\n testing to see if %hu got put into register %u from memory, registerfile was: %hu.", memory_getByte(mm, address, &error), regnum, registerFile_getLowByte(rf, regnum, &error));


    printf("\n now testing alu functions!");
    ALUPtr alu;
    RegisterPtr sw = register_initialize();
    alu = alu_initialize(sw, rf);
    regnum = 0xA;
    uchar regnum2 = 0xB;
    word = 0xA;
    ushort word2 = 0xB;

    registerFile_putWord(rf, regnum, word);
    registerFile_putWord(rf, regnum2, word2);
    printf("\n now putting %hu into register %u and %hu into register %u", word, regnum, word2, regnum2);

    alu_putOperandA(alu, registerFile_getWord(rf, regnum, &error));
    alu_putOperandB(alu, registerFile_getWord(rf, regnum2, &error));

    printf("\n operand A should contain %hu and it actually contains %hu", word, alu->A);
    printf("\n operand B should contain %hu and it actually contains %hu", word2, alu->B);

    alu_add(alu);

    printf("\n after the add funtion is called this is the result: %hu", alu->R);

    registerFile_putWord(rf, regnum, alu->R);

    printf("\n then the result is placed in register %u, here is what is in that register: %hu", regnum, registerFile_getWord(rf, regnum, &error));
}

/* Prints a banner with a title. 
void printBanner(char* title)
{
    int i;
    for (i = 0; i < 80; ++i)
    {
        putchar('*');
    }

    printf("\n* %s", title);

    int spaces = 80 - strlen(title) - 3;
    for (i = 0; i < spaces; ++i)
    {
        putchar(' ');
    }

    printf("*\n");

    for (i = 0; i < 80; ++i)
    {
        putchar('*');
    }
}*/
